#include "ohos_resources_utils.h"
#include <cstdlib>
#include "rawfile/raw_file_manager.h"
#include "resourcemanager/ohresmgr.h"
#include "hilog/log.h"
#include <string>

#define  TAG "arkui_demo"
#define LOGI(...) OH_LOG_Print(LOG_APP, LOG_INFO, 0xff00, TAG, __VA_ARGS__)

static napi_env g_GlobalUIEnv = nullptr;

void InitOhosResourcesUtils(napi_env env)
{
    g_GlobalUIEnv = env;
}

static napi_value CreateString(const char *str)
{
    if (g_GlobalUIEnv == nullptr) {
        return nullptr;
    }
    napi_value result = nullptr;
    napi_create_string_utf8(g_GlobalUIEnv, str, NAPI_AUTO_LENGTH, &result);
    return result;
}

static napi_value CreateInt(size_t number)
{
    if (g_GlobalUIEnv == nullptr) {
        return nullptr;
    }
    napi_value result = nullptr;
    napi_create_int32(g_GlobalUIEnv, number, &result);
    return result;
}

static napi_value CreateDouble(float number)
{
    if (g_GlobalUIEnv == nullptr) {
        return nullptr;
    }
    napi_value result = nullptr;
    napi_create_double(g_GlobalUIEnv, number, &result);
    return result;
}

static napi_value GetObjectProperty(napi_value object, const char *name)
{
    napi_value result = nullptr;
    napi_value nameValue = nullptr;

    nameValue = CreateString(name);
    if (nameValue == nullptr) {
        return nullptr;
    }
    napi_get_property(g_GlobalUIEnv, object, nameValue, &result);
    return result;
}

static napi_value GetArkTsResourceManager()
{
    napi_env env = g_GlobalUIEnv;
    napi_value global;
    napi_get_global(env, &global);
    napi_value getContext = GetObjectProperty(global, "getContext");
    napi_value context;
    napi_call_function(env, global, getContext, 0, nullptr, &context);
    return GetObjectProperty(context, "resourceManager");
}

NativeResourceManager *GetNativeResourceManager()
{
    static NativeResourceManager *nativeSourceManager = nullptr;
    if (nativeSourceManager != nullptr) {
        return nativeSourceManager;
    } else {
        napi_env env = g_GlobalUIEnv;
        nativeSourceManager = OH_ResourceManager_InitNativeResourceManager(env, GetArkTsResourceManager());
    }
    return nativeSourceManager;
}

int GetMediaByName(const char *resName, char **resultValue, uint64_t *resultLen, uint32_t density)
{
    NativeResourceManager *manager = GetNativeResourceManager();
    if (manager == nullptr) {
        return -1;
    }
    int result = OH_ResourceManager_GetMediaByName(manager, resName, (uint8_t**)resultValue,
                                                   resultLen, density);
    return result;
}

int GetMediaBase64ByName(const char *resName, char **resultValue, uint64_t *resultLen,
                         uint32_t density)
{
    NativeResourceManager *manager = GetNativeResourceManager();
    if (manager == nullptr) {
        return -1;
    }
    int result = OH_ResourceManager_GetMediaBase64ByName(manager, resName, resultValue, resultLen,
                                                         density);
    (*resultValue)[*resultLen] = 0;
    return result;
}

int GetColorByName(const char *resName, uint32_t *resultValue)
{
    NativeResourceManager *manager = GetNativeResourceManager();
    if (manager == nullptr) {
        return -1;
    }
    int result = OH_ResourceManager_GetColorByName(manager, resName, resultValue);
    return result;
}

int GetStringByName(const char *resName, char **resultValue)
{
    NativeResourceManager *manager = GetNativeResourceManager();
    if (manager == nullptr) {
        return -1;
    }
    int result = OH_ResourceManager_GetStringByName(manager, resName, resultValue);
    return result;
}

int GetFormatStringByName(const char *resName, char **resultValue, const Arg *args, int argCount)
{
    int res = -1;
    NativeResourceManager *manager = GetNativeResourceManager();
    if (manager == nullptr) {
        return res;
    }
    napi_value resourceManager = GetArkTsResourceManager();
    napi_value func = GetObjectProperty(resourceManager, "getStringByNameSync");
    std::vector<napi_value> array(argCount + 1, nullptr);
    array[0] = CreateString(resName);
    for (int i = 1, j = 0; j < argCount; i++, j++) {
        switch (args[j].type) {
            case ARG_INT:
                array[i] = CreateInt(args[j].v.i);
                break;
            case ARG_FLOAT:
                array[i] = CreateDouble(args[j].v.f);
                break;
            case ARG_STR:
                array[i] = CreateString(args[j].v.s);
                break;
            default:
                LOGI("GetFormatStringByName type is error. type : %{public}d", args[j].type);
                break;
        }
    }

    napi_value result;
    napi_status status = napi_call_function(g_GlobalUIEnv, resourceManager, func, array.size(),
                                            array.data(), &result);
    if (status != napi_ok) {
        LOGI("napi_call_function failed");
        return res;
    }
    size_t strLen = 0;
    status = napi_get_value_string_utf8(g_GlobalUIEnv, result, nullptr, NAPI_AUTO_LENGTH, &strLen);
    if (status != napi_ok && strLen <= 0) {
        LOGI("get string length error");
        return res;
    }
    *resultValue = (char *)malloc(strLen * sizeof(char));
    napi_get_value_string_utf8(g_GlobalUIEnv, result, *resultValue, strLen, &strLen);
    res = 0;
    return res;
}

int GetStringPluralByName(const char *resName, uint32_t num, char **resultValue)
{
    NativeResourceManager *manager = GetNativeResourceManager();
    if (manager == nullptr) {
        return -1;
    }
    LOGI("%{public}s %{public}d", resName, num);
    int result = OH_ResourceManager_GetPluralStringByName(manager, resName, num, resultValue);
    return result;
}

int GetFormatStringPluralByName(const char *resName, uint32_t num, char **resultValue,
                                const Arg *args, int argCount)
{
    int res = -1;
    NativeResourceManager *manager = GetNativeResourceManager();
    if (manager == nullptr) {
        return res;
    }
    napi_value resourceManager = GetArkTsResourceManager();
    napi_value func = GetObjectProperty(resourceManager, "getIntPluralStringByNameSync");
    std::vector<napi_value> array(argCount + 2, nullptr);
    array[0] = CreateString(resName);
    array[1] = CreateInt(num);
    for (int i = 2, j = 0; j < argCount; j++, i++) {
        switch (args[j].type) {
            case ARG_INT:
                array[i] = CreateInt(args[j].v.i);
                break;
            case ARG_FLOAT:
                array[i] = CreateDouble(args[j].v.f);
                break;
            case ARG_STR:
                array[i] = CreateString(args[j].v.s);
                break;
            default:
                LOGI("GetFormatStringByName type is error. type : %{public}d", args[j].type);
                break;
        }
    }

    napi_value result;
    napi_status status = napi_call_function(g_GlobalUIEnv, resourceManager, func, array.size(),
                                            array.data(), &result);
    if (status != napi_ok) {
        LOGI("napi_call_function failed");
        return res;
    }
    size_t strLen = 0;
    status = napi_get_value_string_utf8(g_GlobalUIEnv, result, nullptr, NAPI_AUTO_LENGTH, &strLen);
    if (status != napi_ok && strLen <= 0) {
        LOGI("get string length error");
        return res;
    }
    *resultValue = (char *)malloc(strLen * sizeof(char));
    napi_get_value_string_utf8(g_GlobalUIEnv, result, *resultValue, strLen, &strLen);
    res = 0;
    return res;
}

int GetDrawableDescriptorByName(const char *resName, ArkUI_DrawableDescriptor **drawableDescriptor,
                                uint32_t density = 0, uint32_t type = 0)
{
    NativeResourceManager *manager = GetNativeResourceManager();
    if (manager == nullptr) {
        return -1;
    }
    int result = OH_ResourceManager_GetDrawableDescriptorByName(manager, resName, drawableDescriptor,
                                                                density, type);
    return result;
}

int GetSymbolByName(const char *resName,uint32_t *resultValue)
{
    NativeResourceManager *manager = GetNativeResourceManager();
    if (manager == nullptr) {
        return -1;
    }
    int result = OH_ResourceManager_GetSymbolByName(manager, resName, resultValue);
    return result;
}

int GetIntByName(const char *resName,int *resultValue)
{
    NativeResourceManager *manager = GetNativeResourceManager();
    if (manager == nullptr) {
        return -1;
    }
    int result = OH_ResourceManager_GetIntByName(manager, resName, resultValue);
    return result;
}

int GetFloatByName(const char *resName,float *resultValue)
{
    NativeResourceManager *manager = GetNativeResourceManager();
    if (manager == nullptr) {
        return -1;
    }
    int result = OH_ResourceManager_GetFloatByName(manager, resName, resultValue);
    return result;
}

int GetBoolByName(const char *resName,bool *resultValue)
{
    NativeResourceManager *manager = GetNativeResourceManager();
    if (manager == nullptr) {
        return -1;
    }
    int result = OH_ResourceManager_GetBoolByName(manager, resName, resultValue);
    return result;
}

int GetFileByName(const char *resName, char **resultValue, size_t *bytes)
{
    NativeResourceManager *manager = GetNativeResourceManager();
    if (manager == nullptr) {
        return -1;
    }
    RawFile *rawFile = OH_ResourceManager_OpenRawFile(manager, resName);
    if (rawFile == nullptr) {
        LOGI("GetFileByName rawFile is nullptr");
        return -1;
    }
    *bytes = OH_ResourceManager_GetRawFileRemainingLength(rawFile);
    if (*resultValue == nullptr) {
        *resultValue = (char *)malloc((*bytes) * sizeof(char));
    }
    int length = OH_ResourceManager_ReadRawFile(rawFile, *resultValue, *bytes);
    if (length != *bytes) {
        LOGI("length != bytes");
        free(*resultValue);
        OH_ResourceManager_CloseRawFile(rawFile);
        return -1;
    }
    OH_ResourceManager_CloseRawFile(rawFile);
    return 0;
}

int GetFile64ByName(const char *resName, char **resultValue, uint64_t *bytes)
{
    NativeResourceManager *manager = GetNativeResourceManager();
    if (manager == nullptr) {
        return -1;
    }
    RawFile64 *rawFile64 = OH_ResourceManager_OpenRawFile64(manager, resName);
    if (rawFile64 == nullptr) {
        return -1;
    }
    *bytes = OH_ResourceManager_GetRawFileRemainingLength64(rawFile64);
    if (*resultValue == nullptr) {
        *resultValue = (char *)malloc((*bytes + 1) * sizeof(char));
    }
    uint64_t length = OH_ResourceManager_ReadRawFile64(rawFile64, *resultValue, *bytes);
    (*resultValue)[length] = 0;
    OH_ResourceManager_CloseRawFile64(rawFile64);
    return 0;
}